home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / sketch / source / appleevent / oslhelpers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  60.4 KB  |  2,456 lines

  1. /****************************************************************************
  2.  * 
  3.  * OSLHelpers.c
  4.  *
  5.  ****************************************************************************/
  6.  
  7. #include <string.h>                // for strncmp()
  8. #include <stdio.h>                // for sprintf()
  9.  
  10. #include "OSLHelpers.h"
  11.  
  12. #include "Sounds.h"
  13. #include "StringUtils.h"
  14.  
  15. #include "AERCoreSuite.h"
  16.  
  17. #include "DocumentADT.h"
  18. #include "DocumentHelpers.h"
  19.  
  20. #include "WindowUtils.h"
  21.  
  22. #include "ElementADT.h"
  23. #include "ElementHelpers.h"
  24.  
  25. #include "Assertion.h"
  26.  
  27. #include "OSLClassGraphicObject.h"
  28. #include "OSLClassWindow.h"
  29. #include "OSLClassDocument.h"
  30.  
  31. // --------------------------------------------------------------------------
  32. // file globals
  33.  
  34.  
  35. static ColorRecord fgColorTable[] = 
  36.     {
  37.         {"Black",                    eBlack,        kRGBBlack        },
  38.         {"White",                    eWhite,        kRGBWhite        },
  39.         
  40.         {"Red",                        eRed,            kRGBRed            },
  41.         {"Blue",                        eBlue,        kRGBBlue            },
  42.         {"Green",                    eGreen,        kRGBGreen        },
  43.         
  44.         {"Cyan",                        eCyan,        kRGBCyan            },
  45.         {"Magenta",                    eMagenta,    kRGBMagenta        },
  46.         {"Yellow",                   eYellow,        kRGBYellow        },
  47.         
  48.         {"Olive",                    eOlive,        kRGBOlive        },
  49.         {"Purple",                    ePurple,        kRGBPurple        },
  50.         {"Orange",                    eOrange,        kRGBOrange        },
  51.         {"Brown",                    eBrown,        kRGBBrown        },
  52.  
  53.         {"Gray 1",                    eGray01,       kRGBGray01        },
  54.         {"Gray 2",                    eGray02,       kRGBGray02        },
  55.         {"Gray 3",                    eGray03,       kRGBGray03        },
  56.         {"Gray 4",                    eGray04,       kRGBGray04        },
  57.         {"Gray 5",                    eGray05,       kRGBGray05        },
  58.         {"Gray 6",                    eGray06,       kRGBGray06        },
  59.         {"Gray 7",                    eGray07,       kRGBGray07        },
  60.         {"Gray 8",                    eGray08,       kRGBGray08        },
  61.         {"Gray 9",                    eGray09,       kRGBGray09        },
  62.         {"Gray 10",                    eGray10,       kRGBGray10        },
  63.         {"Gray 11",                    eGray11,       kRGBGray11        },
  64.         {"Gray 12",                    eGray12,       kRGBGray12        },
  65.         {"Gray 13",                    eGray13,       kRGBGray13        },
  66.         {"Gray 14",                    eGray14,       kRGBGray14        },
  67.         {"Gray 15",                    eGray15,       kRGBGray15        },
  68.         {"Gray 16",                    eGray16,       kRGBGray16        },
  69.     };
  70.     
  71. static short fgNumColors = sizeof(fgColorTable) / sizeof(ColorRecord);
  72.  
  73. // ----------------------------------------------------------------------------------------
  74. //                                Object callback functions
  75. // ----------------------------------------------------------------------------------------
  76.  
  77. static pascal OSErr 
  78. OSLCountObjectsCallback              (DescType          desiredType,
  79.                                             DescType          containerClass,
  80.                                             const AEDesc     *container,
  81.                                            long                 *result);
  82.  
  83. static pascal OSErr 
  84. OSLCompareObjectsCallback           (DescType             comparisonOperator, 
  85.                                             const AEDesc     *object,
  86.                                             const AEDesc     *descriptorOrObject, 
  87.                                             Boolean             *result);
  88.                                     
  89. // ----------------------------------------------------------------------------------------
  90. //                Comparison functions used by OSLCompareObjectsCallback()
  91. // ----------------------------------------------------------------------------------------
  92.  
  93. static OSErr
  94. OSLCompareText                          (DescType         oper, 
  95.                                             const AEDesc     *desc1, 
  96.                                             const AEDesc     *desc2, 
  97.                                             Boolean             *result);
  98.  
  99. static OSErr 
  100. OSLCompareEnumeration              (DescType         oper, 
  101.                                             const AEDesc     *desc1, 
  102.                                             const AEDesc     *desc2, 
  103.                                             Boolean             *result);
  104.  
  105. static OSErr 
  106. OSLCompareInteger                      (DescType         oper, 
  107.                                             const AEDesc     *desc1, 
  108.                                             const AEDesc     *desc2, 
  109.                                             Boolean             *result);
  110.  
  111. static OSErr 
  112. OSLCompareFixed                      (DescType         oper, 
  113.                                             const AEDesc     *desc1, 
  114.                                             const AEDesc     *desc2, 
  115.                                             Boolean             *result);
  116.  
  117. static OSErr 
  118. OSLCompareFloat                      (DescType         oper, 
  119.                                             const AEDesc     *desc1, 
  120.                                             const AEDesc     *desc2, 
  121.                                             Boolean             *result);
  122.  
  123. static OSErr 
  124. OSLCompareBoolean                      (DescType         oper, 
  125.                                             const AEDesc     *desc1, 
  126.                                             const AEDesc     *desc2, 
  127.                                             Boolean             *result);
  128.  
  129. static OSErr 
  130. OSLCompareRGBColor                  (DescType         oper, 
  131.                                             const AEDesc     *desc1, 
  132.                                             const AEDesc     *desc2, 
  133.                                             Boolean             *result);
  134.  
  135. static OSErr 
  136. OSLComparePoint                     (DescType         oper, 
  137.                                             const AEDesc     *desc1, 
  138.                                             const AEDesc     *desc2, 
  139.                                             Boolean             *result);
  140.  
  141. static OSErr 
  142. OSLCompareRect                      (DescType         oper, 
  143.                                             const AEDesc     *desc1, 
  144.                                             const AEDesc     *desc2, 
  145.                                             Boolean             *result);
  146.  
  147. // ----------------------------------------------------------------------------------------
  148. //                                    Coercion Handlers
  149. // ----------------------------------------------------------------------------------------
  150.  
  151. static pascal OSErr 
  152. CoerceColorNameToRGBColor(
  153.         const AEDesc     *fromDesc,
  154.         DescType            toType,
  155.        long                handlerRefCon,
  156.         AEDesc             *result);
  157.  
  158. static pascal OSErr 
  159. CoerceColorCodeToRGBColor(
  160.         const AEDesc     *fromDesc,
  161.         DescType            toType,
  162.        long                handlerRefCon,
  163.         AEDesc             *result);
  164.  
  165. static pascal OSErr 
  166. CoerceRGBColorToColorName(
  167.         const AEDesc     *fromDesc,
  168.         DescType            toType,
  169.        long                handlerRefCon,
  170.         AEDesc             *result);
  171.  
  172. static pascal OSErr 
  173. CoerceTypeToEnumeration(
  174.         const AEDesc     *fromDesc,
  175.         DescType            toType,
  176.        long                handlerRefCon,
  177.         AEDesc             *result);
  178.  
  179. static pascal OSErr 
  180. CoerceEnumerationToType(
  181.         const AEDesc     *fromDesc,
  182.         DescType            toType,
  183.        long                handlerRefCon,
  184.         AEDesc             *result);
  185.         
  186. //----------------------------------------------------------------------------------
  187. //    Converts descriptor dataHandle  to a DescType
  188. //----------------------------------------------------------------------------------
  189.  
  190. OSErr 
  191. DescToDescType(const AEDesc *desc, DescType *descType)
  192. {
  193.     OSErr        error = noErr;
  194.         
  195.     if (GetHandleSize(desc->dataHandle) == 4)
  196.         *descType = *(DescType*)*(desc->dataHandle);
  197.     else
  198.         error = errAECoercionFail;
  199.  
  200.     return error;
  201. }
  202.  
  203. //----------------------------------------------------------------------------------
  204. //    Converts descriptor dataHandle  to a boolean
  205. //----------------------------------------------------------------------------------
  206.  
  207. OSErr 
  208. DescToBoolean(const AEDesc* desc, Boolean* aBoolean)
  209. {
  210.     AEDesc    tempDesc     = {typeNull, nil};
  211.     Handle    dataHandle     = nil;
  212.     
  213.     if (desc->descriptorType == typeBoolean)
  214.     {
  215.         dataHandle = desc->dataHandle;
  216.     }
  217.     else
  218.     {
  219.         if (AECoerceDesc(desc, typeBoolean, &tempDesc) == noErr)
  220.             dataHandle = tempDesc.dataHandle;
  221.         else
  222.             return errAECoercionFail;
  223.     }
  224.     
  225.     *aBoolean = **dataHandle;
  226.     
  227.     AEDisposeDesc(&tempDesc);
  228.     
  229.     return(noErr);
  230. }
  231.  
  232. //----------------------------------------------------------------------------------
  233. //    Converts descriptor dataHandle  to a Fixed
  234. //----------------------------------------------------------------------------------
  235.  
  236. OSErr 
  237. DescToFixed(const  AEDesc* desc, Fixed* aFixed)
  238. {
  239.     AEDesc    tempDesc     = {typeNull, nil};
  240.     Handle    dataHandle     = nil;
  241.     
  242.     if (desc->descriptorType == typeFixed)
  243.     {
  244.         dataHandle = desc->dataHandle;
  245.     }
  246.     else
  247.     {
  248.         if (AECoerceDesc(desc, typeFixed, &tempDesc) == noErr)
  249.             dataHandle = tempDesc.dataHandle;
  250.         else
  251.             return errAECoercionFail;
  252.     }
  253.     
  254.     *aFixed = *(Fixed *)*dataHandle;
  255.     
  256.     AEDisposeDesc(&tempDesc);
  257.     
  258.     return(noErr);
  259. }
  260.  
  261. //----------------------------------------------------------------------------------
  262. //    Converts descriptor dataHandle  to a float
  263. //----------------------------------------------------------------------------------
  264.  
  265. OSErr 
  266. DescToFloat(const  AEDesc* desc, float* aFloat)
  267. {
  268.     AEDesc    tempDesc     = {typeNull, nil};
  269.     Handle    dataHandle     = nil;
  270.         
  271.     if (desc->descriptorType == typeFloat)
  272.     {
  273.         dataHandle = desc->dataHandle;
  274.     }
  275.     else
  276.     {
  277.         if (AECoerceDesc(desc, typeFloat, &tempDesc) == noErr)
  278.             dataHandle = tempDesc.dataHandle;
  279.         else
  280.             return errAECoercionFail;
  281.     }    
  282.     
  283.     *aFloat = **(float**)dataHandle;
  284.     
  285.     AEDisposeDesc(&tempDesc);
  286.     
  287.     return(noErr);
  288. }
  289.  
  290. //----------------------------------------------------------------------------------
  291. //    Converts descriptor dataHandle  to a long
  292. //----------------------------------------------------------------------------------
  293.  
  294. OSErr 
  295. DescToLong(const  AEDesc* desc, long* aLong)
  296. {
  297.     AEDesc    tempDesc     = {typeNull, nil};
  298.     Handle    dataHandle     = nil;
  299.     
  300.     if (desc->descriptorType == typeLongInteger)
  301.     {
  302.         dataHandle = desc->dataHandle;
  303.     }
  304.     else
  305.     {
  306.         if (AECoerceDesc(desc, typeLongInteger, &tempDesc) == noErr)
  307.             dataHandle = tempDesc.dataHandle;
  308.         else
  309.             return errAECoercionFail;
  310.     }
  311.     
  312.     *aLong = *(long *)*dataHandle;
  313.     
  314.     AEDisposeDesc(&tempDesc);
  315.     
  316.     return(noErr);
  317. }
  318.  
  319. //----------------------------------------------------------------------------------
  320. //    gets two shorts out of a AEDesc which is an OSA Range Descriptor record
  321. // for an Error range.
  322. //----------------------------------------------------------------------------------
  323.  
  324. OSErr
  325. DescToOSARange(const AEDesc *desc, short *start, short *end)
  326. {
  327.     OSErr        error            = noErr;
  328.     AEDesc    tempDesc     = {typeNull, NULL};
  329.  
  330.     Size        actualSize;
  331.     DescType    actualType;
  332.     
  333.     *start = 0;
  334.     *end   = 0;
  335.     
  336.     error = AECoerceDesc(desc, typeAERecord, &tempDesc);
  337.     if (error != noErr)
  338.     {
  339.         error = errAECoercionFail;
  340.         goto CleanUp;
  341.     }
  342.     
  343.     error = AEGetKeyPtr(&tempDesc, 
  344.                                 keyOSASourceStart,
  345.                                 typeWildCard, 
  346.                                 &actualType, 
  347.                                 start,
  348.                                 sizeof(short), 
  349.                                 &actualSize);
  350.  
  351.     if (error != noErr)
  352.     {
  353.         error = errAECoercionFail;
  354.         goto CleanUp;
  355.     }
  356.  
  357.     error = AEGetKeyPtr(&tempDesc, 
  358.                                 keyOSASourceEnd,
  359.                                 typeWildCard, 
  360.                                 &actualType, 
  361.                                 end,
  362.                                 sizeof(short), 
  363.                                 &actualSize);
  364.  
  365.     if (error != noErr)
  366.     {
  367.         error = errAECoercionFail;
  368.         goto CleanUp;
  369.     }    
  370.  
  371. CleanUp:
  372.     
  373.     AEDisposeDesc(&tempDesc);
  374.  
  375.     return error;
  376. }
  377.  
  378. //----------------------------------------------------------------------------------
  379. //    Converts descriptor dataHandle  to a Point 
  380. //----------------------------------------------------------------------------------
  381.  
  382. OSErr 
  383. DescToPoint(const  AEDesc* desc, Point* aPoint)
  384. {
  385.     AEDesc    tempDesc     = {typeNull, nil};
  386.     Handle    dataHandle     = nil;
  387.     
  388.     if (desc->descriptorType == typeQDPoint)
  389.     {
  390.         dataHandle = desc->dataHandle;
  391.     }
  392.     else
  393.     {
  394.         if (AECoerceDesc(desc, typeQDPoint, &tempDesc) == noErr)
  395.             dataHandle = tempDesc.dataHandle;
  396.         else
  397.             return errAECoercionFail;
  398.     }
  399.     
  400.     *aPoint = *(Point *)*dataHandle;
  401.     
  402.     AEDisposeDesc(&tempDesc);
  403.     
  404.     return(noErr);
  405. }
  406. //----------------------------------------------------------------------------------
  407. //    Converts descriptor dataHandle  to a pascal string
  408. //----------------------------------------------------------------------------------
  409.  
  410. OSErr 
  411. DescToPString(const AEDesc* desc, Str255 aPString, short maxLength)
  412. {
  413.     AEDesc    tempDesc     = {typeNull, nil};
  414.     Handle    dataHandle     = nil;
  415.     long        charCount;
  416.     
  417.     if (desc->descriptorType == typeChar)
  418.     {
  419.         dataHandle = desc->dataHandle;
  420.     }
  421.     else
  422.     {
  423.         if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr)
  424.             dataHandle = tempDesc.dataHandle;
  425.         else
  426.             return errAECoercionFail;
  427.     }
  428.     
  429.     charCount = GetHandleSize(dataHandle);
  430.     
  431.     if (charCount > maxLength)
  432.     {
  433.         AEDisposeDesc(&tempDesc);
  434.         return errAECoercionFail;
  435.     }
  436.  
  437.     HLock(dataHandle);
  438.     BlockMoveData(*dataHandle, &aPString[1], charCount);
  439.     HUnlock(dataHandle);
  440.  
  441.     aPString[0] = charCount;
  442.     
  443.     AEDisposeDesc(&tempDesc);
  444.  
  445.     return(noErr);
  446. }
  447.  
  448. //----------------------------------------------------------------------------------
  449. //    Converts descriptor dataHandle  to a Rectangle 
  450. //----------------------------------------------------------------------------------
  451.  
  452. OSErr 
  453. DescToRect(const  AEDesc* desc, Rect* aRect)
  454. {
  455.     AEDesc    tempDesc     = {typeNull, nil};
  456.     Handle    dataHandle     = nil;
  457.     
  458.     if (desc->descriptorType == typeRectangle)
  459.     {
  460.         dataHandle = desc->dataHandle;
  461.     }
  462.     else
  463.     {
  464.         if (AECoerceDesc(desc, typeQDRectangle, &tempDesc) == noErr)
  465.             dataHandle = tempDesc.dataHandle;
  466.         else
  467.             return errAECoercionFail;
  468.     }
  469.     
  470.     *aRect = *(Rect *)*dataHandle;
  471.     
  472.     AEDisposeDesc(&tempDesc);
  473.     
  474.     return(noErr);
  475. }
  476.  
  477. //----------------------------------------------------------------------------------
  478. //    Converts descriptor dataHandle  to a RGBColor 
  479. //----------------------------------------------------------------------------------
  480.  
  481. OSErr 
  482. DescToRGBColor(const  AEDesc* desc, RGBColor* aRGBColor)
  483. {
  484.     AEDesc    tempDesc     = {typeNull, nil};
  485.     Handle    dataHandle     = nil;
  486.     
  487.     if (desc->descriptorType == typeRGBColor)    // a color value
  488.     {
  489.         dataHandle = desc->dataHandle;
  490.     }
  491.     else    {
  492.         if (AECoerceDesc(desc, typeRGBColor, &tempDesc) == noErr)
  493.             dataHandle = tempDesc.dataHandle;
  494.         else
  495.             return errAECoercionFail;
  496.     }
  497.     
  498.     *aRGBColor = *(RGBColor *)*dataHandle;
  499.     
  500.     AEDisposeDesc(&tempDesc);
  501.     
  502.     return noErr;
  503. }
  504.  
  505. //----------------------------------------------------------------------------------
  506. //    Converts descriptor dataHandle  to a short.
  507. //----------------------------------------------------------------------------------
  508.  
  509. OSErr 
  510. DescToShort(const  AEDesc* desc, short* aShort)
  511. {
  512.     AEDesc    tempDesc     = {typeNull, nil};
  513.     Handle    dataHandle     = nil;
  514.     
  515.     if (desc->descriptorType == typeShortInteger)
  516.     {
  517.         dataHandle = desc->dataHandle;
  518.     }
  519.     else
  520.     {
  521.         if (AECoerceDesc(desc, typeShortInteger, &tempDesc) == noErr)
  522.             dataHandle = tempDesc.dataHandle;
  523.         else
  524.             return errAECoercionFail;
  525.     }
  526.     
  527.     *aShort = *(short *)*dataHandle;
  528.     
  529.     AEDisposeDesc(&tempDesc);
  530.     
  531.     return noErr;
  532. }
  533.  
  534. //----------------------------------------------------------------------------------
  535. //    Converts descriptor dataHandle  to a short double
  536. //----------------------------------------------------------------------------------
  537.  
  538. OSErr 
  539. DescToShortDouble(const  AEDesc* desc, short double* aShortDouble)
  540. {
  541.     AEDesc    tempDesc     = {typeNull, nil};
  542.     Handle    dataHandle     = nil;
  543.         
  544.     if (desc->descriptorType == typeFloat)
  545.     {
  546.         dataHandle = desc->dataHandle;
  547.     }
  548.     else
  549.     {
  550.         if (AECoerceDesc(desc, typeFloat, &tempDesc) == noErr)
  551.             dataHandle = tempDesc.dataHandle;
  552.         else
  553.             return errAECoercionFail;
  554.     }    
  555.     
  556.     *aShortDouble = **(short double**)dataHandle;
  557.     
  558.     AEDisposeDesc(&tempDesc);
  559.     
  560.     return(noErr);
  561. }
  562.  
  563. //----------------------------------------------------------------------------------
  564. //    Copies descriptor dataHandle to another handle, if its text
  565. //----------------------------------------------------------------------------------
  566.  
  567. OSErr 
  568. DescToTextHandle(const AEDesc* desc, Handle *text)
  569. {
  570.     AEDesc    tempDesc     = {typeNull, nil};
  571.     Handle    dataHandle  = nil;
  572.     
  573.     if (desc->descriptorType == typeChar)
  574.     {
  575.         dataHandle = desc->dataHandle;
  576.     }
  577.     else
  578.     {
  579.         if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr)
  580.             dataHandle = tempDesc.dataHandle;
  581.         else
  582.             return errAECoercionFail;
  583.     }
  584.     
  585.     HLock(dataHandle);
  586.     HandToHand(&dataHandle);
  587.     HUnlock(dataHandle);
  588.     
  589.     *text = dataHandle;
  590.  
  591.     AEDisposeDesc(&tempDesc);
  592.  
  593.     return(noErr);
  594. }
  595.  
  596. #pragma mark -
  597. // ---------------------------------------------------------------------------
  598. //                                            Token ADT
  599. // ---------------------------------------------------------------------------
  600. // The following set of utility routines extract the requested data element
  601. // from a CoreTokenRecord. This could be done with a bunch of ugly casts
  602. // sprinkled throughout the code, but these functins provide greater readability.
  603. // ---------------------------------------------------------------------------
  604. //
  605. //    Here's our token data type, a handle to which is stored in the token.dataHandle:
  606. //
  607. //        typedef struct CoreToken_TAG
  608. //        {
  609. //            DescType                dispatchClass;        // same as descriptorType, except for property tokens
  610. //            Boolean                usePropertyCode;
  611. //            DescType                propertyCode;
  612. //            long                    documentNumber;
  613. //            unsigned long        elementNumber;
  614. //            DescType                elementType;
  615. //            long                    beginOffset;
  616. //            long                    endOffset;
  617. //            AEDescList            listOfObjects;
  618. //            FSSpec                fsSpec;
  619. //        } CoreTokenRecord;
  620.  
  621. // ---------------------------------------------------------------------------
  622.  
  623. DescType
  624. ExtractDispatchClassFromToken(const AEDesc *token)
  625. {
  626.  
  627.     DescType dispatchClass             = typeNull;
  628.     CoreTokenHandle  tokenData     = (CoreTokenHandle)(token->dataHandle);
  629.     
  630.     if (tokenData != nil)
  631.         dispatchClass = (**tokenData).dispatchClass;
  632.     
  633.     return dispatchClass;
  634.  
  635. }
  636.  
  637. // ---------------------------------------------------------------------------
  638.  
  639. DescType
  640. ExtractObjectClassFromToken(const AEDesc *token)
  641. {
  642.  
  643.     DescType           objectClass        = typeNull;
  644.     CoreTokenHandle  tokenData         = (CoreTokenHandle)(token->dataHandle);
  645.     
  646.     if (tokenData != nil)
  647.         objectClass = (**tokenData).objectClass;
  648.     
  649.     return objectClass;
  650.  
  651. }
  652.  
  653. // ---------------------------------------------------------------------------
  654. // The field usePropertyCode has been removed from the token record,
  655. // so we emulate it here by seeing if the propertyCode field is typeNull,
  656. // which is interpreted to mean that this is NOT a property token
  657.  
  658. Boolean
  659. ExtractUsePropertyCodeFromToken(const AEDesc *token)
  660. {
  661.  
  662.     Boolean usePropertyCode         = false;
  663.     CoreTokenHandle  tokenData     = (CoreTokenHandle)(token->dataHandle);
  664.     
  665.     if (tokenData != nil)
  666.         usePropertyCode = ((**tokenData).propertyCode != typeNull);
  667.     
  668.     return usePropertyCode;
  669.  
  670. }
  671.  
  672. // ---------------------------------------------------------------------------
  673.  
  674. DescType
  675. ExtractPropertyCodeFromToken(const AEDesc *token)
  676. {
  677.  
  678.     DescType propertyCode            = typeNull;
  679.     CoreTokenHandle  tokenData     = (CoreTokenHandle)(token->dataHandle);
  680.     
  681.     if (tokenData != nil)
  682.         propertyCode = (**tokenData).propertyCode;
  683.     
  684.     return propertyCode;
  685.  
  686. }
  687.  
  688. // ---------------------------------------------------------------------------
  689.  
  690. long
  691. ExtractDocumentNumberFromToken(const AEDesc *token)
  692. {
  693.  
  694.     long                     documentNumber = 0L;
  695.     CoreTokenHandle  tokenData         = (CoreTokenHandle)(token->dataHandle);
  696.     
  697.     if (tokenData != nil)
  698.         documentNumber = (**tokenData).documentNumber;
  699.     
  700.     return documentNumber;
  701.  
  702. }
  703.  
  704. // ---------------------------------------------------------------------------
  705.  
  706. long
  707. ExtractElementNumberFromToken(const AEDesc *token)
  708. {
  709.  
  710.     long                    elementNumber     = 0;
  711.     CoreTokenHandle    tokenData         = (CoreTokenHandle)(token->dataHandle);
  712.     
  713.     if (tokenData != nil)
  714.         elementNumber = (**tokenData).elementNumber;
  715.     
  716.     return elementNumber;
  717. }
  718.  
  719. // ---------------------------------------------------------------------------
  720.  
  721. WindowPtr
  722. ExtractWindowPtrFromToken(const AEDesc *token)
  723. {
  724.     WindowPtr             window             = nil;
  725.     CoreTokenHandle      tokenData         = (CoreTokenHandle)(token->dataHandle);
  726.     
  727.     if (tokenData != nil)
  728.         window = (**tokenData).window;
  729.     
  730.     return window;
  731.  
  732. }
  733.  
  734. #pragma mark -
  735. // ---------------------------------------------------------------------------
  736.  
  737. OSErr 
  738. GetDocumentReferenceFromToken(const AEDesc *token, DocumentReference *document)
  739. {
  740.     OSErr    error             = noErr;
  741.     
  742.     long    documentNumber = ExtractDocumentNumberFromToken(token);
  743.  
  744.     error = GetDocumentByDocumentNumber(documentNumber, document);
  745.  
  746.     if (error != noErr || *document == nil)
  747.         error = errAENoSuchObject;
  748.     
  749.     return error;
  750.  
  751. }
  752.  
  753. //----------------------------------------------------------------------------------
  754.  
  755. OSErr 
  756. GetElementReferenceFromToken(const AEDesc *token, ElementReference *element)
  757. {
  758.     OSErr                        error                = noErr;
  759.     DocumentReference        document            = nil;
  760.     unsigned long            elementNumber    = ExtractElementNumberFromToken(token);
  761.     
  762.     error = GetDocumentReferenceFromToken(token, &document);
  763.         
  764.     if (error == noErr)
  765.         *element = GetElementByNumber(GetDocumentElementList(document), elementNumber);
  766.  
  767.  
  768.     if (error != noErr || *element == nil)
  769.         error = errAENoSuchObject;
  770.     
  771.     return error;
  772.  
  773. }
  774.  
  775. #pragma mark -
  776. // ----------------------------------------------------------------------------------------
  777. // Install the OSL callback routines defined below
  778. // ----------------------------------------------------------------------------------------
  779.  
  780. Boolean 
  781. InstallObjectCallbackFunctions(void)
  782. {
  783.     OSErr error =
  784.     AESetObjectCallbacks(
  785.          NewOSLCompareProc     (OSLCompareObjectsCallback),
  786.          NewOSLCountProc       (OSLCountObjectsCallback),
  787.          (OSLDisposeTokenUPP)    NULL, 
  788.          (OSLGetMarkTokenUPP)    NULL, 
  789.          (OSLMarkUPP)                NULL, 
  790.          (OSLAdjustMarksUPP)        NULL, 
  791.          (OSLGetErrDescUPP)      NULL);
  792.  
  793.     return (error == noErr);
  794. }
  795.  
  796. // ----------------------------------------------------------------------------------------
  797. // Count the number of objects of the desiredType that are in the container
  798. //
  799. // For completeness, this function has the same structure as the container heirarchy
  800. // for the object model structure for the application.
  801. //
  802. // ----------------------------------------------------------------------------------------
  803.  
  804. static pascal OSErr 
  805. OSLCountObjectsCallback(DescType          desiredType,         // class of elements to count
  806.                                 DescType          containerClass,    // container class ID
  807.                                 const AEDesc     *container,         // token for container
  808.                                long                 *result)                // the number we counted
  809. {
  810.     OSErr                     error     = noErr;
  811.     DocumentReference        document;
  812.     ElementReference     element;
  813.     ElementList                elementList;
  814.     
  815.     switch (containerClass) 
  816.     {
  817.         case cApplication:
  818.         case typeNull:
  819.             switch (desiredType)
  820.             {
  821.                 case cDocument:
  822.                     *result = CountDocuments(GetDocumentList());
  823.                     break;
  824.                 
  825.                 case cWindow:
  826.                     *result = CountWindows();
  827.                     break;
  828.                 
  829.                 default:
  830.                     error = errAECantHandleClass;
  831.                     break;
  832.             }
  833.             break;
  834.                 
  835.         case cDocument:
  836.             error = GetDocumentReferenceFromToken(container, &document);
  837.             if (error != noErr)
  838.                 goto CleanUp;
  839.         
  840.             elementList = GetDocumentElementList(document);
  841.             if (elementList == nil)
  842.             {
  843.                 error = errAEEventNotHandled;
  844.                 goto CleanUp;
  845.             }
  846.             
  847.             switch (desiredType)
  848.             {
  849.                 case cGroupedGraphic:                    
  850.                 case cGraphicObject:
  851.                 case cGraphicLine:
  852.                 case cRectangle:
  853.                 case cRoundedRectangle:
  854.                 case cOval:
  855.                 case cPolygon:
  856.                     *result = CountElementsByClass(elementList, desiredType);
  857.                     break;
  858.                     
  859.                 default:
  860.                     error = errAECantHandleClass;
  861.             }
  862.             break;
  863.                     
  864.         case cGroupedGraphic:
  865.             error = GetDocumentReferenceFromToken(container, &document);
  866.             if (error != noErr)
  867.                 goto CleanUp;
  868.                 
  869.             error = GetElementReferenceFromToken(container, &element);
  870.             if (error != noErr)
  871.                 goto CleanUp;
  872.         
  873.             elementList = GetSubElementList(element);
  874.             if (elementList == nil)
  875.             {
  876.                 error = errAEEventNotHandled;
  877.                 goto CleanUp;
  878.             }
  879.             
  880.             switch (desiredType)
  881.             {
  882.                 case cGroupedGraphic:                    
  883.                 case cGraphicObject:
  884.                 case cGraphicLine:
  885.                 case cRectangle:
  886.                 case cRoundedRectangle:
  887.                 case cOval:
  888.                 case cPolygon:
  889.                     *result = CountElementsByClass(elementList, desiredType);
  890.                     break;
  891.                     
  892.                 default:
  893.                     error = errAECantHandleClass;
  894.             }
  895.             break;
  896.                     
  897.         default:
  898.             error = errAECantHandleClass;
  899.             break;
  900.     }
  901.  
  902. CleanUp:
  903.  
  904.     return error;
  905. }
  906.  
  907. // ----------------------------------------------------------------------------------------
  908. // Perform testing against two objects -- used by OSL to resolve complex specifier tests
  909. // ----------------------------------------------------------------------------------------
  910.  
  911. static pascal OSErr 
  912. OSLCompareObjectsCallback (DescType             comparisonOperator,     // operator to use
  913.                                     const AEDesc     *object,                        // left-hand side
  914.                                     const AEDesc     *descriptorOrObject,     // right-hand side
  915.                                     Boolean             *result)
  916. {
  917.     OSErr    error     = noErr;
  918.  
  919.     AEDesc    desc1    = {typeNull, NULL};
  920.     AEDesc    desc2    = {typeNull, NULL};
  921.     AEDesc    temp     = {typeNull, NULL};
  922.     
  923.     // This first AEDesc is a token to a specific object, so we resolve it.
  924.     
  925.     error = ExtractData(object, &desc1);
  926.     if (error != noErr)
  927.         goto CleanUp;
  928.         
  929.     // A second AEDesc is either a token to another object or an AEDesc containing literal data.
  930.     
  931.     error = ExtractData(descriptorOrObject, &desc2);    
  932.     if (error != noErr)
  933.         goto CleanUp;
  934.  
  935.     // Make sure the data type extracted from the second AEDesc is the same as the
  936.     // data specified by the first AEDesc.
  937.     
  938.     // Create a temporary duplicate of desc2 and coerce it to the
  939.     // requested type. This could call a coercion handler you have
  940.     // installed. If there are no errors, stuff the coerced value back into desc2
  941.     
  942.     if (desc1.descriptorType != desc2.descriptorType) 
  943.     {
  944.         error = AEDuplicateDesc(&desc2, &temp);
  945.         if (error != noErr)
  946.             goto CleanUp;
  947.             
  948.         error = AECoerceDesc(&temp, desc1.descriptorType, &desc2);
  949.         if (error != noErr)
  950.             goto CleanUp;
  951.     }
  952.     
  953.     // Now that we know that the 2 types are the same, compare them
  954.     // This has to handle all the data types used in the application's
  955.     // object model implementation.
  956.  
  957.     switch(desc1.descriptorType) 
  958.     {
  959.         case typeChar:
  960.             error = OSLCompareText(comparisonOperator, &desc1, &desc2, result);
  961.             break;
  962.         
  963.         case typeShortInteger:        // also covers typeSMInt        'shor'
  964.         case typeLongInteger:        // also covers typeInteger        'long'
  965.         case typeMagnitude:            //                                        'magn'
  966.             error = OSLCompareInteger(comparisonOperator, &desc1, &desc2, result);
  967.             break;
  968.  
  969.         case typeEnumerated:
  970.             error = OSLCompareEnumeration(comparisonOperator, &desc1, &desc2, result);
  971.             break;
  972.         
  973.         case typeFixed:
  974.             error = OSLCompareFixed(comparisonOperator, &desc1, &desc2, result);
  975.             break;
  976.  
  977.         case typeFloat:
  978.             error = OSLCompareFloat(comparisonOperator, &desc1, &desc2, result);
  979.             break;
  980.         
  981.         case typeBoolean:
  982.             error = OSLCompareBoolean(comparisonOperator, &desc1, &desc2, result);
  983.             break;
  984.                 
  985.         case typeRGBColor:
  986.             error = OSLCompareRGBColor(comparisonOperator, &desc1, &desc2, result);
  987.             break;
  988.                 
  989.         case typeQDRectangle:
  990.             error = OSLCompareRect(comparisonOperator, &desc1, &desc2, result);
  991.             break;
  992.                 
  993.         case typeQDPoint:
  994.             error = OSLComparePoint(comparisonOperator, &desc1, &desc2, result);
  995.             break;
  996.                 
  997.         default:
  998.             error = errAEWrongDataType;
  999.     }
  1000.  
  1001. CleanUp:
  1002.     
  1003.     AEDisposeDesc(&desc1);
  1004.     AEDisposeDesc(&desc2);
  1005.     AEDisposeDesc(&temp);
  1006.     
  1007.     return error;
  1008. }
  1009.  
  1010. #pragma mark -
  1011. // ----------------------------------------------------------------------------------------
  1012.  
  1013. static OSErr
  1014. OSLCompareText(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1015. {
  1016.     OSErr    error = noErr;
  1017.  
  1018.     short    compareResult;
  1019.     char  *lhs;
  1020.     char  *rhs;
  1021.     long    lhsSize;
  1022.     long    rhsSize;
  1023.     
  1024.     lhsSize = GetHandleSize(desc1->dataHandle);
  1025.     MoveHHi(desc1->dataHandle);
  1026.     HLock(desc1->dataHandle);
  1027.     lhs = *(desc1->dataHandle);
  1028.     
  1029.     rhsSize = GetHandleSize(desc2->dataHandle);
  1030.     MoveHHi(desc2->dataHandle);
  1031.     HLock(desc2->dataHandle);
  1032.     rhs = *(desc2->dataHandle);
  1033.  
  1034.     compareResult = CompareText(lhs, rhs, lhsSize, rhsSize, nil);
  1035.  
  1036.     switch (oper) 
  1037.     {
  1038.         case kAEEquals:
  1039.             *result = (compareResult == 0);
  1040.             break;
  1041.         
  1042.         case kAELessThan:
  1043.             *result = (compareResult < 0);
  1044.             break;
  1045.         
  1046.         case kAELessThanEquals:
  1047.             *result = (compareResult <= 0);
  1048.             break;
  1049.         
  1050.         case kAEGreaterThan:
  1051.             *result = (compareResult > 0);
  1052.             break;
  1053.         
  1054.         case kAEGreaterThanEquals:
  1055.             *result = (compareResult >= 0);
  1056.             break;
  1057.         
  1058.         case kAEBeginsWith:
  1059.             if (rhsSize > lhsSize)
  1060.             {
  1061.                 *result = false;
  1062.             }
  1063.             else
  1064.             {
  1065.                 // compare only the number of characters in rhs
  1066.                 // begin comparing at the beginning of lhs
  1067.                 compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
  1068.                 *result = (compareResult == 0);
  1069.             }
  1070.             break;
  1071.             
  1072.         case kAEEndsWith:
  1073.             if (rhsSize > lhsSize)
  1074.             {
  1075.                 *result = false;
  1076.             }
  1077.             else
  1078.             {
  1079.                 // compare only the number of characters in rhs
  1080.                 // begin comparing rhsSize characters from the end of lhs
  1081.                 // start 
  1082.                 
  1083.                 lhs += (lhsSize - rhsSize);
  1084.                 compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
  1085.                 *result = (compareResult == 0);
  1086.             }
  1087.             break;
  1088.  
  1089.         case kAEContains:
  1090.             // Here I use an inefficient search strategy, but we're dealing with small amounts
  1091.             // of text and by using CompareText(), we're doing the same style of comparison
  1092.             // as in the other cases above.
  1093.             
  1094.             *result = false;
  1095.             while (lhsSize >= rhsSize)
  1096.             {
  1097.                 compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
  1098.                 if (compareResult == 0)
  1099.                 {
  1100.                     *result = true;
  1101.                     break;
  1102.                 }
  1103.                 lhs++;
  1104.                 lhsSize--;
  1105.             }
  1106.             break;
  1107.  
  1108.         default:
  1109.             error = errAEBadTestKey;
  1110.     }
  1111.  
  1112.     return error;
  1113. }
  1114.  
  1115. // ----------------------------------------------------------------------------------------
  1116.  
  1117. static OSErr 
  1118. OSLCompareEnumeration(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1119. {
  1120.     OSErr        error    = noErr;
  1121.     long         lhs;
  1122.     long       rhs;
  1123.     AEDesc     charDesc = {typeNull, nil};
  1124.     
  1125.     // Make each number is a long integer (in case it's a short integer or other integer type) 
  1126.     // before extracting the data */
  1127.     
  1128.     error = AECoerceDesc(desc1, typeChar, &charDesc);
  1129.     if (error != noErr)
  1130.         goto CleanUp;
  1131.  
  1132.     lhs = **(long **)(charDesc.dataHandle);
  1133.     AEDisposeDesc(&charDesc);
  1134.     
  1135.     error = AECoerceDesc(desc2, typeChar, &charDesc);
  1136.     if (error != noErr)
  1137.         goto CleanUp;
  1138.  
  1139.     rhs = **(long **)charDesc.dataHandle;
  1140.     AEDisposeDesc(&charDesc);
  1141.     
  1142.     switch (oper) 
  1143.     {
  1144.         case kAEEquals:
  1145.             *result = (lhs == rhs);    // equality is the only test that makes sense for enumerators
  1146.             break;
  1147.         
  1148.         default:
  1149.             error = errAEBadTestKey;
  1150.     }
  1151.  
  1152. CleanUp:
  1153.     AEDisposeDesc(&charDesc);
  1154.  
  1155.     return error;
  1156. }
  1157.  
  1158. // ----------------------------------------------------------------------------------------
  1159.  
  1160. static OSErr 
  1161. OSLCompareInteger(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1162. {
  1163.     OSErr        error    = noErr;
  1164.     long         lhs;
  1165.     long       rhs;
  1166.     AEDesc     longDesc = {typeNull, nil};
  1167.     
  1168.     // Make each number is a long integer (in case it's a short integer or other integer type) 
  1169.     // before extracting the data */
  1170.     
  1171.     error = AECoerceDesc(desc1, typeLongInteger, &longDesc);
  1172.     if (error != noErr)
  1173.         goto CleanUp;
  1174.  
  1175.     lhs = **(long **)(longDesc.dataHandle);
  1176.     AEDisposeDesc(&longDesc);
  1177.     
  1178.     error = AECoerceDesc(desc2, typeLongInteger, &longDesc);
  1179.     if (error != noErr)
  1180.         goto CleanUp;
  1181.  
  1182.     rhs = **(long **)longDesc.dataHandle;
  1183.     AEDisposeDesc(&longDesc);
  1184.     
  1185.     switch (oper) 
  1186.     {
  1187.         case kAEEquals:
  1188.             *result = (lhs == rhs);
  1189.             break;
  1190.         
  1191.         case kAELessThan:
  1192.             *result = (lhs < rhs);
  1193.             break;
  1194.         
  1195.         case kAELessThanEquals:
  1196.             *result = (lhs <= rhs);
  1197.             break;
  1198.         
  1199.         case kAEGreaterThan:
  1200.             *result = (lhs > rhs);
  1201.             break;
  1202.         
  1203.         case kAEGreaterThanEquals:
  1204.             *result = (lhs >= rhs);
  1205.             break;
  1206.         
  1207.         default:
  1208.             error = errAEBadTestKey;
  1209.     }
  1210.  
  1211. CleanUp:
  1212.     AEDisposeDesc(&longDesc);
  1213.  
  1214.     return error;
  1215. }
  1216.  
  1217. // ----------------------------------------------------------------------------------------
  1218.  
  1219. static OSErr 
  1220. OSLCompareFixed(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1221. {
  1222.     OSErr    error    = noErr;
  1223.  
  1224.     Fixed     lhs;
  1225.     Fixed  rhs;
  1226.     
  1227.     error = DescToFixed(desc1, &lhs);
  1228.     if (error != noErr)
  1229.         return error;
  1230.         
  1231.     error = DescToFixed(desc2, &rhs);
  1232.     if (error != noErr)
  1233.         return error;
  1234.     
  1235.     switch (oper) 
  1236.     {
  1237.         case kAEEquals:
  1238.             *result = (lhs == rhs);
  1239.             break;
  1240.         
  1241.         case kAELessThan:
  1242.             *result = (lhs < rhs);
  1243.             break;
  1244.         
  1245.         case kAELessThanEquals:
  1246.             *result = (lhs <= rhs);
  1247.             break;
  1248.         
  1249.         case kAEGreaterThan:
  1250.             *result = (lhs > rhs);
  1251.             break;
  1252.         
  1253.             case kAEGreaterThanEquals:
  1254.             *result = (lhs >= rhs);
  1255.             break;
  1256.         
  1257.         default:
  1258.             error = errAEBadTestKey;
  1259.     }
  1260.     
  1261.     return error;
  1262. }
  1263.  
  1264. // ----------------------------------------------------------------------------------------
  1265.  
  1266. static OSErr 
  1267. OSLCompareFloat(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1268. {
  1269.     OSErr    error    = noErr;
  1270.  
  1271.     float     lhs;
  1272.     float  rhs;
  1273.     
  1274.     error = DescToFloat(desc1, &lhs);
  1275.     if (error != noErr)
  1276.         return error;
  1277.         
  1278.     error = DescToFloat(desc2, &rhs);
  1279.     if (error != noErr)
  1280.         return error;
  1281.     
  1282.     switch (oper) 
  1283.     {
  1284.         case kAEEquals:
  1285.             *result = (lhs == rhs);
  1286.             break;
  1287.         
  1288.         case kAELessThan:
  1289.             *result = (lhs < rhs);
  1290.             break;
  1291.         
  1292.         case kAELessThanEquals:
  1293.             *result = (lhs <= rhs);
  1294.             break;
  1295.         
  1296.         case kAEGreaterThan:
  1297.             *result = (lhs > rhs);
  1298.             break;
  1299.         
  1300.             case kAEGreaterThanEquals:
  1301.             *result = (lhs >= rhs);
  1302.             break;
  1303.         
  1304.         default:
  1305.             error = errAEBadTestKey;
  1306.     }
  1307.     
  1308.     return error;
  1309. }
  1310.  
  1311. // ----------------------------------------------------------------------------------------
  1312. // Apple events defines a boolean as a 1-byte value containing 1 for TRUE and 0 for FALSE
  1313.  
  1314. static OSErr 
  1315. OSLCompareBoolean(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1316. {
  1317.     OSErr    err     = noErr;
  1318.     
  1319.     Boolean bool1    = ((**(char **)desc1->dataHandle) != 0);
  1320.     Boolean bool2    = ((**(char **)desc2->dataHandle) != 0);
  1321.         
  1322.     if (oper == kAEEquals) 
  1323.         *result = (bool1 == bool2);
  1324.     else
  1325.         err = errAEBadTestKey;        // No other tests make sense
  1326.  
  1327.     return err;
  1328. }
  1329.  
  1330. // ----------------------------------------------------------------------------------------
  1331.  
  1332. static OSErr 
  1333. OSLCompareRGBColor(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1334. {
  1335.     OSErr    error = noErr;
  1336.     
  1337.     RGBColor lhs;
  1338.     RGBColor rhs;
  1339.     
  1340.     error = DescToRGBColor(desc1, &lhs);
  1341.     if (error != noErr)
  1342.         return error;
  1343.         
  1344.     error = DescToRGBColor(desc2, &rhs);
  1345.     if (error != noErr)
  1346.         return error;
  1347.  
  1348.     if (oper == kAEEquals) 
  1349.         *result = EqualRGB(lhs, rhs);
  1350.     else
  1351.         error = errAEBadTestKey;        // No other tests make sense
  1352.  
  1353.     return error;
  1354. }
  1355.  
  1356. // ----------------------------------------------------------------------------------------
  1357.  
  1358. static OSErr 
  1359. OSLComparePoint(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1360. {
  1361.     OSErr    error = noErr;
  1362.     
  1363.     Point lhs;
  1364.     Point rhs;
  1365.     
  1366.     error = DescToPoint(desc1, &lhs);
  1367.     if (error != noErr)
  1368.         return error;
  1369.         
  1370.     error = DescToPoint(desc2, &rhs);
  1371.     if (error != noErr)
  1372.         return error;
  1373.         
  1374.     switch (oper)
  1375.     {
  1376.         case kAEEquals:
  1377.             *result = (lhs.h = rhs.h && lhs.v == rhs.v);
  1378.             break;
  1379.             
  1380.         case kAELessThan:
  1381.             *result = (lhs.h < rhs.h && lhs.v < rhs.v);
  1382.             break;
  1383.         
  1384.         case kAELessThanEquals:
  1385.             *result = (lhs.h <= rhs.h && lhs.v <= rhs.v);
  1386.             break;
  1387.         
  1388.         case kAEGreaterThan:
  1389.             *result = (lhs.h > rhs.h && lhs.v > rhs.v);
  1390.             break;
  1391.         
  1392.         case kAEGreaterThanEquals:
  1393.             *result = (lhs.h >= rhs.h && lhs.v >= rhs.v);
  1394.             break;
  1395.         
  1396.         default:
  1397.             error = errAEBadTestKey;        // No other tests make sense
  1398.     }
  1399.  
  1400.     return error;
  1401. }
  1402.  
  1403. // ----------------------------------------------------------------------------------------
  1404.  
  1405. static OSErr 
  1406. OSLCompareRect(DescType oper, const AEDesc *desc1, const AEDesc *desc2, Boolean *result)
  1407. {
  1408.     OSErr    error = noErr;
  1409.     
  1410.     Rect lhs;
  1411.     Rect rhs;
  1412.     
  1413.     error = DescToRect(desc1, &lhs);
  1414.     if (error != noErr)
  1415.         return error;
  1416.         
  1417.     error = DescToRect(desc2, &rhs);
  1418.     if (error != noErr)
  1419.         return error;
  1420.         
  1421.     switch (oper)
  1422.     {
  1423.         // compare size AND location
  1424.         case kAEEquals:    
  1425.             *result = ((lhs.top == rhs.top) && (lhs.left == rhs.left) && (lhs.bottom == rhs.bottom) && (lhs.right == rhs.right));
  1426.             break;
  1427.             
  1428.         // compare size only on the rest of the tests
  1429.         case kAELessThan:    
  1430.             *result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
  1431.             break;
  1432.         
  1433.         case kAELessThanEquals:
  1434.             *result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
  1435.             break;
  1436.         
  1437.         case kAEGreaterThan:
  1438.             *result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
  1439.             break;
  1440.         
  1441.         case kAEGreaterThanEquals:
  1442.             *result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
  1443.             break;
  1444.         
  1445.         case kAEContains:
  1446.             // Note: two identical Rects contain each other, according to this test:
  1447.             *result = ((lhs.top <= rhs.top) && (lhs.left <= rhs.left) && (lhs.bottom >= rhs.bottom) && (lhs.right >= rhs.right));
  1448.             break;
  1449.             
  1450.         default:
  1451.             error = errAEBadTestKey;        // No other tests make sense
  1452.     }
  1453.  
  1454.     return error;
  1455. }
  1456.  
  1457. #pragma mark -
  1458. // -------------------------------------------------------------------------------------------
  1459. //
  1460. //  ExtractKeyDataParameter
  1461. //
  1462. // Extract the keyData parameter data from an apple event
  1463. // -------------------------------------------------------------------------------------------
  1464.  
  1465. OSErr 
  1466. ExtractKeyDataParameter(const AppleEvent *appleEvent, AEDesc *data)
  1467. {
  1468.     OSErr     error         = noErr;
  1469.     AEDesc    keyData      = {typeNull, nil};
  1470.  
  1471.     error = AEGetKeyDesc(appleEvent, keyAEData, typeWildCard, &keyData);
  1472.  
  1473.     if (error == noErr)
  1474.         error = ExtractData(&keyData, data);
  1475.     
  1476.     AEDisposeDesc(&keyData);
  1477.     
  1478.     return error;
  1479. }
  1480.  
  1481. // ----------------------------------------------------------------------------------------
  1482. // ExtractData can receive several types of data:
  1483. //    Source                     Processing
  1484. //    --------------------  -----------------------------
  1485. //     an Object specifier   call AEResolve() to get token, then handle below
  1486. //        a property token      call public accessors to get raw data from token
  1487. //    a object token        if it's not a property token, the token itself is returned
  1488. //    raw data                     just return it, it's already data!
  1489. // ----------------------------------------------------------------------------------------
  1490.  
  1491. OSErr
  1492. ExtractData(const AEDesc *source, AEDesc *data)
  1493. {
  1494.     OSErr        error         = noErr;
  1495.     AEDesc    temp             = {typeNull, nil};
  1496.     DescType    dispatchClass;
  1497.         
  1498.     if ((source->descriptorType == typeNull) || (source->dataHandle == nil))
  1499.     {
  1500.         error = errAENoSuchObject;
  1501.         goto CleanUp;
  1502.     }
  1503.     
  1504.     // If it's an object specifier, resolve into a token
  1505.     // Otherwise, just copy it
  1506.     
  1507.     if (source->descriptorType == typeObjectSpecifier) 
  1508.     {
  1509.         error = AEResolve(source, kAEIDoMinimum, &temp);
  1510.     }
  1511.     else
  1512.     {
  1513.         error = AEDuplicateDesc(source, &temp);
  1514.     }
  1515.     if (error != noErr) 
  1516.         goto CleanUp;
  1517.     
  1518.     // Next, determine which object should handle it, if any. 
  1519.     // If it's a property token, get the dispatch class. 
  1520.     // Otherwise, just get the descriptorType. 
  1521.     
  1522.     if (temp.descriptorType == typeProperty)
  1523.     {
  1524.         dispatchClass = ExtractDispatchClassFromToken(&temp);
  1525.     }
  1526.     else
  1527.         dispatchClass = temp.descriptorType;
  1528.     
  1529.     // If it's a property token, get the data it refers to,
  1530.     // otherwise duplicate it and return
  1531.     
  1532.     // EXPANSION NOTE: When you add a new class, 
  1533.     // you must add it to this switch statement
  1534.     
  1535.     switch (dispatchClass) 
  1536.     {
  1537.         case cApplication:
  1538.             error = errAEEventNotHandled;
  1539.             break;
  1540.             
  1541.         case cDocument:
  1542.             error = GetDataFromDocument(&temp, NULL, data);        
  1543.             break;
  1544.             
  1545.         case cWindow:
  1546.             error = GetDataFromWindow(&temp, NULL, data);        
  1547.             break;
  1548.  
  1549.         case cGraphicObject:
  1550.              error = GetDataFromGraphicObject(&temp, NULL, data);        
  1551.             break;
  1552.             
  1553.         default:            // This is raw data or an non-property token
  1554.             error = AEDuplicateDesc(&temp, data);
  1555.             break;
  1556.     }
  1557.  
  1558. CleanUp:
  1559.  
  1560.     AEDisposeDesc(&temp);
  1561.         
  1562.     return error;
  1563. }
  1564.  
  1565. // -------------------------------------------------------------------------------------------
  1566. //
  1567. //  ResolveObjectSpecifier
  1568. //
  1569. // Given an ospec, return a token
  1570. // -------------------------------------------------------------------------------------------
  1571.  
  1572. OSErr 
  1573. ResolveObjectSpecifier(const AEDesc *source, AEDesc *data)
  1574. {
  1575.     OSErr error = noErr;
  1576.     
  1577.     if (source->descriptorType == typeObjectSpecifier) 
  1578.     {
  1579.         error = AEResolve(source, kAEIDoMinimum, data);
  1580.     }
  1581.     else
  1582.     {
  1583.         Assert(kAssertAlways, "ResolveObjectSpecifier() received bad data.");
  1584.         error = errAENotAnObjSpec;
  1585.     }
  1586.     
  1587.     return error;
  1588. }
  1589.  
  1590. #pragma mark -
  1591. // ----------------------------------------------------------------------------------------
  1592. //                                                    Object Specifier Helpers
  1593. //-----------------------------------------------------------------------------------------
  1594.  
  1595. OSErr CreateElementOSpec(DocumentReference document, ElementReference element, AEDesc *ospec)
  1596. {
  1597.  
  1598.     OSErr        error            = noErr;
  1599.     
  1600.     AEDesc    documentOSpec    = {typeNull, nil};
  1601.     AEDesc    objectIndex        = {typeNull, nil};
  1602.     
  1603.     long            index        = 0L;
  1604.     
  1605.     ElementType elementType;
  1606.     DescType        objectClass;
  1607.     
  1608.     // First, get the ospec for the document
  1609.     
  1610.     error = CreateDocumentOSpec(document, &documentOSpec);
  1611.     
  1612.     // Now, get the index of the object
  1613.     
  1614.     if (error == noErr)
  1615.     {
  1616.         elementType = GetElementType(element);
  1617.         
  1618.         index = GetIndexForElementType(document, element, elementType);
  1619.         if (index == 0L)
  1620.             error = errAENoSuchObject;
  1621.     }
  1622.     
  1623.     if (error == noErr)
  1624.         error = AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(index), &objectIndex);
  1625.     
  1626.     // Create the complete object specifier for the graphic object
  1627.             
  1628.     if (error == noErr)
  1629.         error = ConvertElementTypeToObjectClass(elementType, &objectClass);
  1630.  
  1631.     if (error == noErr)
  1632.         error = CreateObjSpecifier(objectClass,                    // desired class
  1633.                                             &documentOSpec,                 // container object
  1634.                                             formAbsolutePosition,        // keyForm
  1635.                                             &objectIndex,                     // index of this object
  1636.                                             false,                             // dispose inputs?
  1637.                                             ospec);                            // resulting object specifier
  1638.     
  1639.     AEDisposeDesc(&documentOSpec);
  1640.     AEDisposeDesc(&objectIndex);
  1641.         
  1642.     return error;
  1643. }
  1644.  
  1645. //----------------------------------------------------------------------------------
  1646.  
  1647. OSErr CreateElementUniqueIDOSpec(DocumentReference document, ElementReference element, AEDesc *ospec)
  1648. {
  1649.  
  1650.     OSErr            error                = noErr;
  1651.     
  1652.     AEDesc        documentOSpec    = {typeNull, nil};
  1653.     AEDesc        objectID          = {typeNull, nil};
  1654.     
  1655.     long            uniqueID            = 0L;
  1656.     
  1657.     ElementType elementType;
  1658.     DescType        objectClass;
  1659.     
  1660.     elementType = GetElementType(element);
  1661.     uniqueID    = GetElementNumber(element);
  1662.  
  1663.     // First, get the ospec for the document
  1664.     
  1665.     error = CreateDocumentOSpec(document, &documentOSpec);
  1666.         
  1667.     if (error == noErr)
  1668.     {
  1669.         error = AECreateDesc(typeLongInteger, (Ptr)&uniqueID, sizeof(uniqueID), &objectID);
  1670.     }
  1671.     
  1672.     // Create the complete object specifier for the graphic object
  1673.             
  1674.     if (error == noErr)
  1675.         error = ConvertElementTypeToObjectClass(elementType, &objectClass);
  1676.  
  1677.     if (error == noErr)
  1678.         error = CreateObjSpecifier(objectClass,                    // desired class
  1679.                                             &documentOSpec,                 // container object
  1680.                                             formUniqueID,                    // keyForm
  1681.                                             &objectID,                         // index of this object
  1682.                                             false,                             // dispose inputs?
  1683.                                             ospec);                            // resulting object specifier
  1684.     
  1685.     AEDisposeDesc(&documentOSpec);
  1686.     AEDisposeDesc(&objectID);
  1687.         
  1688.     return error;
  1689. }
  1690.  
  1691. //----------------------------------------------------------------------------------
  1692.  
  1693. OSErr CreateGraphicObjectOSpec(DocumentReference document, ElementReference element, AEDesc *ospec)
  1694. {
  1695.  
  1696.     OSErr        error            = noErr;
  1697.     
  1698.     AEDesc    documentOSpec    = {typeNull, nil};
  1699.     AEDesc    objectIndex        = {typeNull, nil};
  1700.     
  1701.     long            index        = 0L;
  1702.     
  1703.     ElementType elementType;
  1704.     DescType        objectClass;
  1705.     
  1706.     // First, get the ospec for the document
  1707.     
  1708.     error = CreateDocumentOSpec(document, &documentOSpec);
  1709.     
  1710.     // Now, get the index of the object
  1711.     
  1712.     if (error == noErr)
  1713.     {
  1714.         elementType = GetElementType(element);
  1715.         
  1716.         index = GetIndexForElementType(document, element, elementType);
  1717.         if (index == 0L)
  1718.             error = errAENoSuchObject;
  1719.     }
  1720.     
  1721.     if (error == noErr)
  1722.         error = AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(index), &objectIndex);
  1723.     
  1724.     // Create the complete object specifier for the graphic object
  1725.             
  1726.     if (error == noErr)
  1727.         error = ConvertElementTypeToObjectClass(elementType, &objectClass);
  1728.  
  1729.     if (error == noErr)
  1730.         error = CreateObjSpecifier(objectClass,                    // desired class
  1731.                                             &documentOSpec,                 // container object
  1732.                                             formAbsolutePosition,        // keyForm
  1733.                                             &objectIndex,                     // index of this object
  1734.                                             false,                             // dispose inputs?
  1735.                                             ospec);                            // resulting object specifier
  1736.     
  1737.     AEDisposeDesc(&documentOSpec);
  1738.     AEDisposeDesc(&objectIndex);
  1739.         
  1740.     return error;
  1741. }
  1742.  
  1743. //----------------------------------------------------------------------------------
  1744.  
  1745. OSErr CreateGraphicGroupMemberOSpec(DocumentReference document, ElementReference element, ElementReference subElement, AEDesc *ospec)
  1746. {
  1747.  
  1748.     OSErr        error                = noErr;
  1749.     
  1750.     AEDesc    groupOSpec        = {typeNull, nil};
  1751.     AEDesc    objectIndex        = {typeNull, nil};
  1752.     
  1753.     long            index        = 0L;
  1754.     
  1755.     ElementType elementType;
  1756.     DescType        objectClass;
  1757.     
  1758.     // First, get the ospec for the graphic group object
  1759.     
  1760.     error = CreateGraphicObjectOSpec(document, element, &groupOSpec);
  1761.     
  1762.     // Now, get the index of the subelement object
  1763.     
  1764.     if (error == noErr)
  1765.     {
  1766.         elementType = GetElementType(subElement);
  1767.         
  1768.         index = GetIndexForSubElementType(document, element, subElement, elementType);
  1769.         if (index == 0L)
  1770.             error = errAENoSuchObject;
  1771.     }
  1772.     
  1773.     if (error == noErr)
  1774.         error = AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(index), &objectIndex);
  1775.     
  1776.     // Create the complete object specifier for the graphic object
  1777.             
  1778.     if (error == noErr)
  1779.         error = ConvertElementTypeToObjectClass(elementType, &objectClass);
  1780.  
  1781.     if (error == noErr)
  1782.         error = CreateObjSpecifier(objectClass,                    // desired class
  1783.                                             &groupOSpec,                    // container object
  1784.                                             formAbsolutePosition,        // keyForm
  1785.                                             &objectIndex,                     // index of this object
  1786.                                             false,                             // dispose inputs?
  1787.                                             ospec);                            // resulting object specifier
  1788.     
  1789.     AEDisposeDesc(&groupOSpec);
  1790.     AEDisposeDesc(&objectIndex);
  1791.         
  1792.     return error;
  1793. }
  1794.  
  1795. //----------------------------------------------------------------------------------
  1796.  
  1797. OSErr CreateDocumentOSpec(DocumentReference document, AEDesc *ospec)
  1798. {
  1799.  
  1800.     OSErr        error;
  1801.     
  1802.     AEDesc    appObj    = {typeNull, nil};
  1803.     AEDesc    docObj    = {typeNull, nil};
  1804.     
  1805.     Str63        docName;
  1806.  
  1807.     // Create the reference to the document by name
  1808.     
  1809.     GetDocumentName(document, docName);
  1810.     
  1811.     error = AECreateDesc(typeChar, (Ptr)&docName[1], docName[0], &docObj);
  1812.     
  1813.     // Create the complete object specifier for document by name
  1814.             
  1815.     error = CreateObjSpecifier(cDocument,             // desired class
  1816.                                         &appObj,             // container object
  1817.                                         formName,             // keyForm
  1818.                                         &docObj,             // this object
  1819.                                         false,                 // dispose inputs?
  1820.                                         ospec);                // resulting object specifier
  1821.     
  1822.     AEDisposeDesc(&docObj);
  1823.     AEDisposeDesc(&appObj);
  1824.         
  1825.     return error;
  1826. }
  1827.  
  1828.  
  1829. // ---------------------------------------------------------------------------
  1830. //    CreateRangeDescriptorOSpec
  1831. // ---------------------------------------------------------------------------
  1832.  
  1833. OSErr
  1834. CreateRangeDescriptorOSpec(const AEDesc* container, DescType desiredClass, long index1, long index2, AEDesc *ospec)
  1835. {
  1836.     OSErr            error    = noErr;
  1837.     OSErr            ignoreError;
  1838.     
  1839.     Boolean        isRange = (index2 > index1);
  1840.     
  1841.     AEDesc        currentContainer     = {typeNull, nil};
  1842.     AEDesc        offset               = {typeNull, nil};
  1843.     AEDesc        startObject            = {typeNull, nil};
  1844.     AEDesc        stopObject            = {typeNull, nil};
  1845.     AEDesc      range               = {typeNull, nil};
  1846.     
  1847.     Assert(index1 >= 1,     "CreateRangeDescriptorOSpec() : index1 must be >= 1");
  1848.     Assert(index2 > index1, "CreateRangeDescriptorOSpec() : index2 must be > index1");
  1849.     
  1850.     // Current container
  1851.     
  1852.     error = AECreateDesc(typeCurrentContainer, nil, 0L, ¤tContainer);
  1853.     
  1854.     //    start object
  1855.  
  1856.     if (error == noErr)
  1857.         error = CreateOffsetDescriptor(index1, &offset);
  1858.  
  1859.     if (error == noErr)
  1860.         error = CreateObjSpecifier(desiredClass, ¤tContainer, formAbsolutePosition, &offset, false, &startObject);
  1861.     
  1862.     ignoreError = AEDisposeDesc(&offset);
  1863.     
  1864.     // stop object
  1865.     
  1866.     if (error == noErr)
  1867.         error = CreateOffsetDescriptor(index2, &offset);
  1868.     
  1869.     if (error == noErr)
  1870.         error = CreateObjSpecifier(desiredClass, ¤tContainer, formAbsolutePosition, &offset, false, &stopObject);
  1871.     
  1872.     ignoreError = AEDisposeDesc(&offset);
  1873.     
  1874.     // Home, home on the range...
  1875.     
  1876.     if (error == noErr)
  1877.         error = CreateRangeDescriptor(&startObject, &stopObject, false, &range);
  1878.     
  1879.     ignoreError = AEDisposeDesc(&startObject);
  1880.     ignoreError = AEDisposeDesc(&stopObject);
  1881.     
  1882.     if (error == noErr)
  1883.         error = CreateObjSpecifier(desiredClass, (AEDesc *)container, formRange, &range, false, ospec);
  1884.  
  1885.     AEDisposeDesc(&range);
  1886.     
  1887.     return error;
  1888. }
  1889.  
  1890. #pragma mark -
  1891. // ----------------------------------------------------------------------------------------
  1892. //                                         typeAEList helper functions
  1893. //----------------------------------------------------------------------------------
  1894.  
  1895. Boolean TokenContainsTokenList(AEDesc *token)
  1896. {
  1897.     return (token->descriptorType == typeAEList);
  1898. }
  1899.  
  1900. // -------------------------------------------------------------------------------------------
  1901. // Note: make sure the result descriptor is {typeNull, nil} when it is passed in to this
  1902.  
  1903. OSErr GetFirstNonListToken(AEDesc *token, AEDesc *result)
  1904. {
  1905.     OSErr         error         = noErr;
  1906.     AEDesc         tempToken    = {typeNull, nil};
  1907.     AEKeyword    keyword;
  1908.     long            numItems;
  1909.     long             itemNum;
  1910.     
  1911.     if (result->descriptorType == typeNull)
  1912.     {
  1913.         if (TokenContainsTokenList(token) == false)
  1914.         {
  1915.             error = AEDuplicateDesc(token, result);
  1916.         }
  1917.         else
  1918.         {
  1919.             error = AECountItems(token, &numItems);
  1920.             
  1921.             for (itemNum = 1; itemNum <= numItems; itemNum++)
  1922.             {
  1923.                 error = AEGetNthDesc((AEDescList *)token, itemNum, typeWildCard, &keyword, &tempToken);
  1924.                 if (error != noErr)
  1925.                     goto CleanUp;
  1926.                     
  1927.                 error = GetFirstNonListToken(&tempToken, result);                
  1928.                 if ((error != noErr) || (result->descriptorType != typeNull))
  1929.                     break;
  1930.                     
  1931.                 AEDisposeDesc(&tempToken);
  1932.             }
  1933.         }
  1934.     }
  1935.     
  1936. CleanUp:
  1937.     if (error != noErr)
  1938.         AEDisposeDesc(result);
  1939.         
  1940.     AEDisposeDesc(&tempToken);
  1941.     
  1942.     return error;
  1943. }
  1944.  
  1945. //----------------------------------------------------------------------------------
  1946. // On entry, flatList must be a valid AEDescList, created with AECreateList function
  1947. // flatList can be an empty list, however.
  1948.  
  1949. OSErr FlattenAEList(AEDescList *deepList, AEDescList *flatList)
  1950. {
  1951.     OSErr            error = noErr;
  1952.     AEDesc        item    = {typeNull, nil};
  1953.     AEKeyword    keyword;
  1954.     long            itemNum;
  1955.     long            numItems;
  1956.  
  1957.     error = AECountItems(deepList, &numItems);
  1958.     if (error != noErr)
  1959.         goto CleanUp;
  1960.     
  1961.     for (itemNum = 1; itemNum <= numItems; itemNum++)
  1962.     {
  1963.         error = AEGetNthDesc(deepList, itemNum, typeWildCard, &keyword, &item);
  1964.         if (error != noErr)
  1965.             goto CleanUp;
  1966.             
  1967.         if (item.descriptorType == typeAEList)
  1968.             error = FlattenAEList(&item, flatList);
  1969.         else
  1970.             error = AEPutDesc(flatList, 0L, &item);
  1971.         
  1972.         if (error != noErr)
  1973.             goto CleanUp;
  1974.             
  1975.         AEDisposeDesc(&item);
  1976.     }
  1977.  
  1978. CleanUp:
  1979.     if (error != noErr)
  1980.         AEDisposeDesc(flatList);
  1981.  
  1982.     AEDisposeDesc(&item);
  1983.     
  1984.     return error;
  1985. }
  1986.  
  1987. /*****************************************************************************
  1988.  * 
  1989.  * EqualRGB
  1990.  * 
  1991.  * Returns true if the two RGB colors are equal
  1992.  * 
  1993.  *****************************************************************************/
  1994. Boolean EqualRGB(RGBColor colorA, RGBColor colorB)
  1995. {
  1996.     return((colorA.red == colorB.red) && (colorA.green == colorB.green) && (colorA.blue == colorB.blue));
  1997. }
  1998.  
  1999. #pragma mark -
  2000. //----------------------------------------------------------------------------------
  2001. // color coercion helpers
  2002. //----------------------------------------------------------------------------------
  2003.  
  2004. Boolean    
  2005. GetColorRecordByName(char *name, ColorRecord *colorRecord)
  2006. {
  2007.     Boolean foundIt = false;
  2008.     short   index;
  2009.  
  2010.     *colorRecord     = fgColorTable[0];        // initialize return value to black
  2011.     
  2012.     for (index = 0; index < fgNumColors; index++)
  2013.     {
  2014.         if (CStringEqual(fgColorTable[index].name, name, false))
  2015.         {
  2016.             *colorRecord     = fgColorTable[index];
  2017.             foundIt     = true;
  2018.             break;
  2019.         }
  2020.     }
  2021.  
  2022.     return foundIt;
  2023. }
  2024.  
  2025.  
  2026. //----------------------------------------------------------------------------------
  2027.  
  2028. Boolean    
  2029. GetColorRecordByCode(DescType code, ColorRecord *colorRecord)
  2030. {
  2031.     Boolean foundIt = false;
  2032.     short   index;
  2033.  
  2034.     *colorRecord     = fgColorTable[0];        // initialize return value to black
  2035.     
  2036.     for (index = 0; index < fgNumColors; index++)
  2037.     {
  2038.         if (fgColorTable[index].code == code)
  2039.         {
  2040.             *colorRecord     = fgColorTable[index];
  2041.             foundIt     = true;
  2042.             break;
  2043.         }
  2044.     }
  2045.  
  2046.     return foundIt;
  2047. }
  2048.  
  2049. //----------------------------------------------------------------------------------
  2050.  
  2051. Boolean    
  2052. GetColorRecordByRGB(RGBColor rgbValue, ColorRecord *colorRecord)
  2053. {
  2054.     Boolean foundIt = false;
  2055.     short   index;
  2056.  
  2057.     *colorRecord = fgColorTable[0];        // initialize return value to black
  2058.     
  2059.     for (index = 0; index < fgNumColors; index++)
  2060.     {
  2061.         if (EqualRGB(rgbValue, fgColorTable[index].rgbValue))
  2062.         {
  2063.             *colorRecord     = fgColorTable[index];
  2064.             foundIt     = true;
  2065.             break;
  2066.         }
  2067.     }
  2068.  
  2069.     return foundIt;
  2070. }
  2071.  
  2072.  
  2073. #pragma mark -
  2074. // ----------------------------------------------------------------------------------------
  2075. //                                    Coercion Handlers
  2076. // ----------------------------------------------------------------------------------------
  2077.  
  2078. Boolean
  2079. InstallCoercionHandlers(void)
  2080. {
  2081.       OSErr error;
  2082.       
  2083.       // color coercions
  2084.       
  2085.       error = AEInstallCoercionHandler(    typeChar,                // fromType
  2086.                                                       typeRGBColor,        // toType
  2087.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceColorNameToRGBColor),
  2088.                                                       0,                            // handler refCon
  2089.                                                       true,                        // fromTypeIsDesc
  2090.                                                       false);                    // isSysHandler
  2091.  
  2092.     if (error == noErr)
  2093.       error = AEInstallCoercionHandler(    typeRGBColor,            // fromType
  2094.                                                       typeChar,                // "as text"
  2095.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceRGBColorToColorName),
  2096.                                                       0,                            // handler refCon
  2097.                                                       true,                        // fromTypeIsDesc
  2098.                                                       false);                    // isSysHandler
  2099.  
  2100.     if (error == noErr)
  2101.       error = AEInstallCoercionHandler(    typeRGBColor,            // fromType
  2102.                                                       typeIntlText,           // "as string"
  2103.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceRGBColorToColorName),
  2104.                                                       0,                            // handler refCon
  2105.                                                       true,                        // fromTypeIsDesc
  2106.                                                       false);                    // isSysHandler
  2107.  
  2108.     if (error == noErr)
  2109.           error = AEInstallCoercionHandler(typeType,               // fromType
  2110.                                                       typeRGBColor,        // toType
  2111.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceColorCodeToRGBColor),
  2112.                                                       0,                            // handler refCon
  2113.                                                       true,                        // fromTypeIsDesc
  2114.                                                       false);                    // isSysHandler
  2115.  
  2116.  
  2117.     if (error == noErr)
  2118.           error = AEInstallCoercionHandler(typeEnumeration,     // fromType
  2119.                                                       typeRGBColor,        // toType
  2120.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceColorCodeToRGBColor),
  2121.                                                       0,                            // handler refCon
  2122.                                                       true,                        // fromTypeIsDesc
  2123.                                                       false);                    // isSysHandler
  2124.  
  2125.  
  2126.     // type to enum, and enum to type
  2127.     
  2128.     if (error == noErr)
  2129.           error = AEInstallCoercionHandler(typeType,               // fromType
  2130.                                                       typeEnumeration,     // toType
  2131.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceTypeToEnumeration),
  2132.                                                       0,                            // handler refCon
  2133.                                                       true,                        // fromTypeIsDesc
  2134.                                                       false);                    // isSysHandler
  2135.  
  2136.  
  2137.     if (error == noErr)
  2138.           error = AEInstallCoercionHandler(typeEnumeration,      // fromType
  2139.                                                       typeType,                // toType
  2140.                                                       (AECoercionHandlerUPP) NewAECoerceDescProc(CoerceEnumerationToType),
  2141.                                                       0,                            // handler refCon
  2142.                                                       true,                        // fromTypeIsDesc
  2143.                                                       false);                    // isSysHandler
  2144.  
  2145.  
  2146.     return (error == noErr);
  2147. }
  2148.  
  2149. // ----------------------------------------------------------------------------------------
  2150. // Coerce a color name to a RGB color value
  2151.  
  2152. static pascal OSErr 
  2153. CoerceColorNameToRGBColor(const AEDesc     *fromDesc,            // fromDesc, the source AEDesc
  2154.                                           DescType   toType,                // toType, the type we want
  2155.                                           long       handlerRefCon,    // refCon
  2156.                                           AEDesc     *result)            // toDesc, the resulting AEDesc
  2157. {
  2158.     #pragma unused (handlerRefCon)
  2159.  
  2160.     OSErr            error            = noErr;
  2161.     ColorRecord    color;
  2162.     
  2163.     char            colorName[80];
  2164.     
  2165.     result->descriptorType     = typeNull;
  2166.     result->dataHandle         = nil;
  2167.     
  2168.      if (fromDesc->descriptorType == typeChar)                        // a color name
  2169.     {
  2170.         TextToCString(fromDesc->dataHandle, colorName, 80);
  2171.         GetColorRecordByName(colorName, &color);
  2172.         error = AECreateDesc(typeRGBColor, &color.rgbValue, sizeof(RGBColor), result);
  2173.     }
  2174.  
  2175.     if (result->descriptorType != toType)
  2176.         error = errAECoercionFail;
  2177.         
  2178.     return error;
  2179. }
  2180.  
  2181. // ----------------------------------------------------------------------------------------
  2182. // Coerce a color enumerator to a RGB color value
  2183.  
  2184. static pascal OSErr 
  2185. CoerceColorCodeToRGBColor(const AEDesc     *fromDesc,            // fromDesc, the source AEDesc
  2186.                                           DescType   toType,                // toType, the type we want
  2187.                                           long       handlerRefCon,    // refCon
  2188.                                           AEDesc     *result)            // toDesc, the resulting AEDesc
  2189. {
  2190.     #pragma unused (handlerRefCon)
  2191.  
  2192.     OSErr                error  = noErr;
  2193.     ColorRecord        color;
  2194.     
  2195.     DescType            code;
  2196.     
  2197.     result->descriptorType     = typeNull;
  2198.     result->dataHandle         = nil;
  2199.     
  2200.      if (fromDesc->descriptorType == typeType || fromDesc->descriptorType == typeEnumeration)                        // a color enumerator
  2201.     {
  2202.         error = DescToDescType((AEDesc *)fromDesc, &code);
  2203.         if (error == noErr)
  2204.         {
  2205.             GetColorRecordByCode(code, &color);
  2206.             error = AECreateDesc(typeRGBColor, &color.rgbValue, sizeof(RGBColor), result);
  2207.         }
  2208.     }
  2209.  
  2210.     if (result->descriptorType != toType)
  2211.         error = errAECoercionFail;
  2212.         
  2213.     return error;
  2214. }
  2215.  
  2216. // ----------------------------------------------------------------------------------------
  2217. // Coerce an RGBCcolor to a color name, as string or as text
  2218.  
  2219. typedef struct IText
  2220. {
  2221.     ScriptCode  theScriptCode;
  2222.     LangCode        theLangCode;
  2223.     char            *theText;
  2224. } IText;
  2225.  
  2226. static pascal OSErr 
  2227. CoerceRGBColorToColorName(const AEDesc     *fromDesc,               // fromDesc, the source AEDesc
  2228.                                           DescType   toType,                // toType, the type we want
  2229.                                           long       handlerRefCon,    // refCon
  2230.                                           AEDesc     *result)            // toDesc, the resulting AEDesc
  2231. {
  2232.     #pragma unused (handlerRefCon)
  2233.  
  2234.     OSErr                error  = noErr;
  2235.     ColorRecord        color;
  2236.     IText                intlText;
  2237.     
  2238.     RGBColor            rgb;
  2239.     Boolean            foundIt;
  2240.     
  2241.     result->descriptorType     = typeNull;
  2242.     result->dataHandle         = nil;
  2243.     
  2244.      if (fromDesc->descriptorType == typeRGBColor)
  2245.     {
  2246.         error = DescToRGBColor((AEDesc *)fromDesc, &rgb);
  2247.         if (error == noErr)
  2248.         {
  2249.             foundIt = GetColorRecordByRGB(rgb, &color);
  2250.             if (foundIt)
  2251.             {
  2252.                 if (toType == typeChar)
  2253.                     error = AECreateDesc(typeChar, color.name, strlen(color.name), result);
  2254.                 else if (toType == typeIntlText)
  2255.                 {
  2256.                     intlText.theScriptCode  = 0;
  2257.                     intlText.theLangCode        = 0;
  2258.                     intlText.theText             = color.name;
  2259.                     
  2260.                     error = AECreateDesc(typeIntlText, &intlText, sizeof(IText), result);
  2261.                 }
  2262.             }
  2263.             else
  2264.             {
  2265.                 char name[80];
  2266.                 sprintf(name, "%d,%d,%d", rgb.red, rgb.blue, rgb.green);
  2267.                 error = AECreateDesc(typeChar, name, strlen(name), result);            
  2268.             }
  2269.         }
  2270.     }
  2271.  
  2272.     if (result->descriptorType != toType)
  2273.         error = errAECoercionFail;
  2274.         
  2275.     return error;
  2276. }
  2277.  
  2278. // ----------------------------------------------------------------------------------------
  2279. // Coerce a typeEnumeration to typeType
  2280.  
  2281. static pascal OSErr 
  2282. CoerceEnumerationToType(  const AEDesc     *fromDesc,            // fromDesc, the source AEDesc
  2283.                                           DescType   toType,                // toType, the type we want
  2284.                                           long       handlerRefCon,    // refCon
  2285.                                           AEDesc     *result)            // toDesc, the resulting AEDesc
  2286. {
  2287.     #pragma unused (handlerRefCon)
  2288.  
  2289.     OSErr                    error  = noErr;
  2290.     DescType                type;
  2291.     
  2292.     result->descriptorType     = typeNull;
  2293.     result->dataHandle         = nil;
  2294.     
  2295.      if (fromDesc->descriptorType == typeEnumeration)
  2296.     {
  2297.         error = DescToDescType((AEDesc *)fromDesc, &type);
  2298.         if (error == noErr)
  2299.             error = AECreateDesc(typeType, &type, sizeof(DescType), result);
  2300.     }
  2301.  
  2302.     if (result->descriptorType != toType)
  2303.         error = errAECoercionFail;
  2304.         
  2305.     return error;
  2306. }
  2307.  
  2308. // ----------------------------------------------------------------------------------------
  2309. // Coerce a typeEnumeration to typeType
  2310.  
  2311. static pascal OSErr 
  2312. CoerceTypeToEnumeration(  const AEDesc     *fromDesc,            // fromDesc, the source AEDesc
  2313.                                           DescType   toType,                // toType, the type we want
  2314.                                           long       handlerRefCon,    // refCon
  2315.                                           AEDesc     *result)            // toDesc, the resulting AEDesc
  2316. {
  2317.     #pragma unused (handlerRefCon)
  2318.  
  2319.     OSErr                    error  = noErr;
  2320.     DescType                enumeration;
  2321.     
  2322.     result->descriptorType     = typeNull;
  2323.     result->dataHandle         = nil;
  2324.     
  2325.      if (fromDesc->descriptorType == typeType)
  2326.     {
  2327.         error = DescToDescType((AEDesc *)fromDesc, &enumeration);
  2328.         if (error == noErr)
  2329.             error = AECreateDesc(typeEnumeration, &enumeration, sizeof(DescType), result);
  2330.     }
  2331.  
  2332.     if (result->descriptorType != toType)
  2333.         error = errAECoercionFail;
  2334.         
  2335.     return error;
  2336. }
  2337.  
  2338. #pragma mark -
  2339. //----------------------------------------------------------------------------------
  2340. // Handles formAbsolutePosition resolution
  2341.  
  2342. OSErr
  2343. NormalizeAbsoluteIndex(const AEDesc *keyData, long *index, long maxIndex, Boolean *isAllItems)
  2344. {
  2345.  
  2346.     OSErr error = noErr;
  2347.     
  2348.     *isAllItems = false;                                                // set to true if we receive kAEAll constant
  2349.     
  2350.     // Extract the formAbsolutePosition data, either a integer or a literal constant
  2351.     
  2352.     switch (keyData->descriptorType)
  2353.     {
  2354.         case typeLongInteger:                                        // positve or negative index
  2355.             if (DescToLong(keyData, index) != noErr)
  2356.                 return errAECoercionFail;
  2357.             break;
  2358.             
  2359.        case typeAbsoluteOrdinal:                                        // 'abso'
  2360.             if (DescToDescType((AEDesc*)keyData, (DescType*)index) != noErr)
  2361.                 return errAECoercionFail;
  2362.             break;
  2363.  
  2364.         default:
  2365.             return errAEWrongDataType;
  2366.             break;
  2367.     }
  2368.  
  2369.     // convert literal to number, or negative index to positive index
  2370.     
  2371.     switch (*index)
  2372.     {
  2373.        case kAEFirst:
  2374.            *index = 1L;
  2375.             break;
  2376.             
  2377.         case kAEMiddle:
  2378.             *index = (maxIndex >> 1) + (maxIndex % 2);
  2379.             break;
  2380.             
  2381.        case kAELast:
  2382.            *index = maxIndex;
  2383.             break;
  2384.             
  2385.        case kAEAny:
  2386.             *index = (TickCount() % maxIndex) + 1;
  2387.             break;
  2388.             
  2389.        case kAEAll:
  2390.            *index      = 1L;
  2391.            *isAllItems = true;
  2392.             break;
  2393.             
  2394.         default:
  2395.             if (*index < 0)                                            // convert a negative index from end of list to a positive index from beginning of list
  2396.             {
  2397.                 *index = maxIndex + *index + 1;
  2398.             }
  2399.            break;
  2400.    }
  2401.  
  2402.     // range-check the new index number
  2403.  
  2404.     if ((*index < 1) || (*index > maxIndex))                    
  2405.     {
  2406.         error = errAEIllegalIndex;
  2407.     }
  2408.  
  2409.    return error;
  2410. }
  2411.  
  2412. //----------------------------------------------------------------------------------
  2413. // Handles formRange resolution of boundary objects
  2414.  
  2415. OSErr 
  2416. ProcessFormRange(AEDesc *keyData, AEDesc *start, AEDesc *stop)
  2417. {
  2418.     OSErr     error            = noErr;
  2419.     AEDesc     rangeRecord = {typeNull, nil};
  2420.     AEDesc    ospec            = {typeNull, nil};
  2421.     
  2422.     // coerce the range record data into an AERecord 
  2423.     
  2424.      error = AECoerceDesc(keyData, typeAERecord, &rangeRecord);
  2425.      if (error != noErr)
  2426.          goto CleanUp;
  2427.      
  2428.     // object specifier for first object in the range
  2429.     
  2430.     error = AEGetKeyDesc(&rangeRecord, keyAERangeStart, typeWildCard, &ospec);
  2431.      if (error == noErr && ospec.descriptorType == typeObjectSpecifier)
  2432.          error = AEResolve(&ospec, kAEIDoMinimum, start);
  2433.          
  2434.      if (error != noErr)
  2435.          goto CleanUp;
  2436.          
  2437.     AEDisposeDesc(&ospec);
  2438.         
  2439.     // object specifier for last object in the range
  2440.     
  2441.     error = AEGetKeyDesc(&rangeRecord, keyAERangeStop, typeWildCard, &ospec);
  2442.       if (error == noErr && ospec.descriptorType == typeObjectSpecifier)
  2443.          error = AEResolve(&ospec, kAEIDoMinimum, stop);
  2444.  
  2445. CleanUp:
  2446.  
  2447.     AEDisposeDesc(&ospec);
  2448.     AEDisposeDesc(&rangeRecord);
  2449.                             
  2450.     return error;
  2451. }
  2452.  
  2453. //----------------------------------------------------------------------------------
  2454.  
  2455.  
  2456.